#!/bin/bash

source ./lib/lib.sh

rpm_dir="rpms"

download_rpms "$PKG_CI_ABS_RPM_URL" "$rpm_dir"

yum install -y $rpm_dir/*

check_and_install_dependencies()
{
	for package_name in "$@"; do
		log_info "Checking package: $package_name"
		rpm -q $package_name || yum install -y $package_name
	done
}

dependencies() {
	check_and_install_dependencies kmod-udma udma accel-config
	log_info "dependencies installed"
}

dependencies

modprobe udma_drv

cat > compression_example.cpp << EOF
/*******************************************************************************
 * Copyright (C) 2022 Intel Corporation
 *
 * SPDX-License-Identifier: MIT
 ******************************************************************************/

//* [QPL_LOW_LEVEL_COMPRESSION_EXAMPLE] */

#include <iostream>
#include <vector>
#include <memory>
#include <stdexcept> // for runtime_error
#include <string>

#include "qpl/qpl.h"

static inline int parse_execution_path(int argc, char **argv, qpl_path_t *path_ptr, int extra_arg = 0) {
    // Get path from input argument
    if (extra_arg == 0) {
        if (argc < 2) {
            std::cout << "Missing the execution path as the first parameter. Use either hardware_path or software_path." << std::endl;
            return 1;
        }
    } else {
        if (argc < 3) {
            std::cout << "Missing the execution path as the first parameter and/or the dataset path as the second parameter." << std::endl;
            return 1;
        }
    }

    std::string path = argv[1];
    if (path == "hardware_path") {
        *path_ptr = qpl_path_hardware;
        std::cout << "The example will be run on the hardware path." << std::endl;
    } else if (path == "software_path") {
        *path_ptr = qpl_path_software;
        std::cout << "The example will be run on the software path." << std::endl;
    } else {
        std::cout << "Unrecognized value for parameter. Use hardware_path or software_path." << std::endl;
        return 1;
    }

    return 0;
}

/**
 * @brief This example requires a command line argument to set the execution path. Valid values are \`software_path\`
 * and \`hardware_path\`.
 * In QPL, @ref qpl_path_software (\`Software Path\`) means that computations will be done with CPU.
 * Accelerator can be used instead of CPU. In this case, @ref qpl_path_hardware (\`Hardware Path\`) must be specified.
 * If there is no difference where calculations should be done, @ref qpl_path_auto (\`Auto Path\`) can be used to allow
 * the library to chose the path to execute. The Auto Path usage is not demonstrated by this example.
 *
 * @warning ---! Important !---
 * \`Hardware Path\` doesn't support all features declared for \`Software Path\`
 *
 */
constexpr const uint32_t source_size = 1000;

auto main(int argc, char** argv) -> int {
    // Default to Software Path
    qpl_path_t execution_path = qpl_path_software;

    // Get path from input argument
    int parse_ret = parse_execution_path(argc, argv, &execution_path);
    if (parse_ret != 0) {
        return 1;
    }

    // Source and output containers
    std::vector<uint8_t> source(source_size, 5);
    std::vector<uint8_t> destination(source_size / 2, 4);
    std::vector<uint8_t> reference(source_size, 7);

    std::unique_ptr<uint8_t[]> job_buffer;
    qpl_status                 status;
    uint32_t                   size = 0;

    // Job initialization
    status = qpl_get_job_size(execution_path, &size);
    if (status != QPL_STS_OK) {
        throw std::runtime_error("An error acquired during job size getting.");
    }

    job_buffer = std::make_unique<uint8_t[]>(size);
    qpl_job *job = reinterpret_cast<qpl_job *>(job_buffer.get());
    status = qpl_init_job(execution_path, job);
    if (status != QPL_STS_OK) {
        throw std::runtime_error("An error acquired during compression job initializing.");
    }

    // Performing a compression operation
    job->op            = qpl_op_compress;
    job->level         = qpl_default_level;
    job->next_in_ptr   = source.data();
    job->next_out_ptr  = destination.data();
    job->available_in  = source_size;
    job->available_out = static_cast<uint32_t>(destination.size());
    job->flags         = QPL_FLAG_FIRST | QPL_FLAG_LAST | QPL_FLAG_DYNAMIC_HUFFMAN | QPL_FLAG_OMIT_VERIFY;

    // Compression
    status = qpl_execute_job(job);
    if (status != QPL_STS_OK) {
        throw std::runtime_error("Error while compression occurred.");
    }

    const uint32_t compressed_size = job->total_out;

    // Performing a decompression operation
    job->op            = qpl_op_decompress;
    job->next_in_ptr   = destination.data();
    job->next_out_ptr  = reference.data();
    job->available_in  = compressed_size;
    job->available_out = static_cast<uint32_t>(reference.size());
    job->flags         = QPL_FLAG_FIRST | QPL_FLAG_LAST;

    // Decompression
    status = qpl_execute_job(job);
    if (status != QPL_STS_OK) {
        throw std::runtime_error("Error while decompression occurred.");
    }

    // Freeing resources
    status = qpl_fini_job(job);
    if (status != QPL_STS_OK) {
        throw std::runtime_error("An error acquired during job finalization.");
    }

    // Compare reference functions
    for (size_t i = 0; i < source.size(); i++) {
        if (source[i] != reference[i]) {
            throw std::runtime_error("Content wasn't successfully compressed and decompressed.");
        }
    }

    std::cout << "Content was successfully compressed and decompressed." << std::endl;
    std::cout << "Compressed size: " << compressed_size << std::endl;

    return 0;
}

//* [QPL_LOW_LEVEL_COMPRESSION_EXAMPLE] */
EOF

g++ -std=c++17 -o compression_example compression_example.cpp -lqpl -ludma
[[ $? -eq 0 ]] && testcase_pass "qpl test compiled passed" || testcase_fail "qpl test compiled failed"

./compression_example software_path && testcase_pass "qpl software test passed" || testcase_fail "qpl software test failed"

# get iax device of the system
device="iax"
device_num=$(ls /sys/bus/dsa/devices/ | grep -e "$device[0-9]" | tr -d '[a-z,:\s/" ]' | head -n 1)
accel-config disable-device $device$device_num

cat > iax.conf <<EOF
[
  {
    "dev": "$device$device_num",
    "groups": [
      {
        "dev": "group$device_num.0",
        "grouped_workqueues": [
          {
            "dev": "wq$device_num.0",
            "type": "user",
            "mode": "dedicated",
            "size": 16,
            "group_id": 0,
            "priority": 10,
            "max_transfer_size": 4194304,
            "name": "iaxtest",
            "block_on_fault":0,
            "driver_name": "user"
          }
        ],
        "grouped_engines": [
          {
            "dev": "engine$device_num.0",
            "group_id": 0
          }
        ]
      }
    ]
  }
]
EOF
accel-config load-config -c iax.conf -ve

./compression_example hardware_path && testcase_pass "qpl hardware test passed" || testcase_skip "qpl hardware test failed"
